/*
 * @author Chris
 * @since 2023/2/7 11:20
 *
 * @brief    The project will ...
 *
 * @note     ...
 *
 * @warning  Do not to ...
 *
 * Change Logs:
 *   Date           Author       Notes
 *   2023/2/7     Chris        the first version
 */
#include "8052.h"

#define _nop_() __asm nop __endasm
#define I2CDelay() _nop_();_nop_();_nop_();_nop_();

#define I2C_SCL  P3_7
#define I2C_SDA  P3_6

void I2CStart() {
    I2C_SCL = 1;
    I2C_SDA = 1;
    I2C_SDA = 0;
    I2CDelay();
    I2C_SCL = 0;
}

void I2CStop() {
    I2C_SCL = 0;
    I2C_SDA = 0;
    I2C_SCL = 1;
    I2CDelay();
    I2C_SDA = 1;
}

__sbit I2CWrite(unsigned char dat) {
    I2C_SCL = 0;
    for (unsigned char mask = 0x80; mask != 0; mask >>= 1) {
        I2C_SDA = (dat & mask) == 0 ? 0 : 1;
        I2C_SCL = 1;
        I2CDelay();
        I2C_SCL = 0;
    }

    I2C_SDA = 1;
    I2C_SCL = 1;
    I2CDelay();
    __sbit ack = I2C_SDA;
    I2C_SCL = 0;
    return ~ack;
}

unsigned char I2CRead(__sbit ack) {
    I2C_SDA = 1;

    unsigned char dat = 0;
    for (unsigned char mask = 0x80; mask != 0; mask >>= 1) {
        I2C_SCL = 1;
        // dat = dat | ((I2C_SDA & mask) == 0 ? 0 : mask);
        dat = I2C_SDA == 0 ? (dat & (~mask)) : (dat | mask);
        I2C_SCL = 0;
        I2CDelay();
    }

    I2C_SCL = 0;
    I2C_SDA = ack;
    I2C_SCL = 1;
    I2CDelay();
    I2C_SCL = 0;
    return dat;
}

unsigned char I2CReadNak() {
    return I2CRead(1);
}

unsigned char I2CReadAck() {
    return I2CRead(0);
}
